这篇文章用来记录自己开发 PureBlue 主题过程中的感想。

先立一个 Flag

博客内容固然是最重要的,但是抛开内容不讲,博客本身也应该带有自己的Tag,而不是光会用别人的轮子。

最早接触的博客平台是 CSDN 和博客园,在上面学习到了很多网友的经验,于是萌发了想要创建自己博客的念头,在写了几篇文章后又觉得:为何不自己搭建一个博客平台呢?因此在今年一月份的寒假捣鼓了 hexo 和 github pages,包括下载各种漂亮的主题、添加各种有意思的插件,一时乐在其中。平静下来之后,我开始进行知识迁移的工作,把以前存放在印象笔记中的东西重新修改并整合,转移到个人博客里,于是内容慢慢充实起来。

直到十几天前,我用的还是 Next 主题,这的确是一个相当成熟和漂亮的主题,我特别喜欢它的简洁。直到某天看到一句话:

当你看到你用的主题出现在两个以上的博客时,那你就要考虑自己写一个了。

别说两个了,Next 主题的用户数应该是目前所有主题中最多的,而博客外观的雷同很显然是一件非常尴尬的事情。正好在那时我也陷入了一个纠结,就是我一直处于知识输入的状态却鲜有项目上的输出,简单地说就是学的多、做的少----这是很要命的事,毕竟“纸上得来终觉浅”。也就是说我面临两个问题:

  • 缺少项目实践
  • 博客主题缺少个性化

这两个问题恰巧有共同的答案,那就是自己制作一个主题。当时想的是这学期能做出来都算好的了,于是立了一个 flag:

不过很欣慰的是,我赶在月底之前把它完成了,前后大约花了14天。(大概是这个 flag 给我的动力)

这是项目地址

体会和感想

虽然是一个小项目,而且代码也写得比较乱,但是收获颇丰——接触到了两个新的技术,一是模板引擎ejs,二个是css预处理器stylus,还有就是对hexo的原理有了更为深入的理解,至少知道了我写的markdown文件是怎么在网页上渲染出来的,而不是光会用却不知道原理。

万事开头难,前期准备工作的时候真的是一头雾水。首先是Hexo的官方文档,写得很不友好,所以读起来云里雾里;其次是不同主题使用的模板引擎和css预编译都不同,主题文件的结构也不同,这大大提高了阅读源码的难度和花在上面的时间成本。虽然经过“搜刮”,我找到了几篇教程,但是大部分还是讲的不够浅显易懂,越看越晕。这时候我意识到两个重要的问题:

  • 这些东西不是给纯新手准备的,我需要先了解基础的概念
  • 善用搜索引擎,不要将视野局限在国内平台

所以我开始去youtube上寻找相关的视频,幸运的是我的确找到了纯新手向的主题制作教程。每集只有几分钟,但是对于理解一些基础概念来说已经足够。不用担心听不懂,因为自带字幕,再配合up主的操作演示,还是很好理解的。

之后我又谷歌了相关的文章,成功找到了这个系列教程,这是目前找到的最详细的教程,真真正正的从零开始教你怎么做一个主题,所以说实话真的很感谢这位老外。为了加深对主题制作的理解以及方便其他有需求的人,我将这个系列翻译了过来,可以在我的博客里找到,当然也可以去Segment Fault。目前我只翻译了两篇,第三篇会另外找个时间搞定。

教程看下来,发现难点主要集中在两个地方:一是理清项目结构,进行合理的组织,二个是设计样式并具体实现。
准备工作差不多之后,就可以开始动工了,不需要太着急,每天完成一部分就行。
印象比较深的难点就是垂直时间轴的制作,也就是下面这个东西:

一个是要做出样式,主要涉及伪元素的使用,以及考虑怎么让垂直轴随着页面高度增加而延长;二个是逻辑,遍历所有文章并根据年份进行划分,这里需要使用ejs的语法,对Hexo的内置变量也要熟悉。

踩了哪些坑 / 部分需求的实现思路

当然,做这个主题的时候也踩了很多坑,这里做一下踩坑记录:

  • 路径问题。为了使代码更容易管理,通常制作主题都是采用模块化的方式,因此存在着大量的文件引用。而A文件引用B文件时,不一定是使用B相对于A的路径,而要看最终A文件被谁引用。

  • 某篇文章中出现了一行很长的代码,因为没有对它进行换行和溢出处理,导致图片尺寸无法正常设置,同时所有的文本内容都被挤出div。

  • 在本地测试的时候某些文章无法显示全文内容,并且底部div消失。这个问题比较奇葩,而且至今无解。猜想应该是渲染出错还是什么= =。

  • 写stylus文件时混用了空格和tab,git报错。(这个是真的坑,开了sublime的提示才看出来的)

  • 第三方插件失效。返回顶部按钮是用的第三方jq插件,坑的地方就在于,作者引用jq库时是用的http链接,被浏览器阻止了,导致插件失效。一开始以为是缓存问题导致的样式无法修改,在反复修改和刷新了一个半小时后才想到去控制台看报错信息:

    所以,为了保险一点还是在项目中放jq文件比较好,当然更好的做法应该是直接用原生js来写。

  • 改动不生效的问题。比较常见的状况,在本地预览一切正常,通过域名访问的时候改动却迟迟没有生效,而且通常的清除浏览器缓存或者hexo clean还不一定有效。只能说改动的同步还是需要时间的= =

  • page页面共用。这个严格来说不算坑,而是应该留意的一个地方。Hexo中并没有专门的展示所有标签或者所有类别的页面,拿我用的ejs来说,layout文件夹下的tag.ejs实际指的是单一标签下的所有文章,同理categories.ejs指的是单一类别下的所有文章。而我们需要的展示页面实际上是统一放在page.ejs中,再根据条件判断生成对应页面。不过我实际操作的时候发现分类页走的是归档页的布局。所以目前这个主题的分类页无法正常工作,也许之后会找到原因吧问题已解决,目前分类页可以正常工作。

  • 在 js 中引用 hexo 的内置变量。做导航栏时需要区分不同类型的页面。这个其实也很好解决,因为页面链接和导航栏条目是一一对应的(比如archive页面的链接是/archive,导航栏条目是archive),所以做一个判断就好。然而尴尬的是,首页压根就没有这种链接,首页就是一个/,尽管有 is_home() 函数可以用,不过 js 里是用不了的。所以这个时候我想到了直接通过配置文件拿到首页的 url,之后再做判断,但是又有一个问题 —— 这是hexo的内置变量,只能在ejs中使用,在js里是不识别的。考虑到ejs会生成dom元素,所以解决的思路是:将内置变量存放在dom元素里并生成,之后在js中获取它的值,并设置该元素不可见 直接作为dom元素的data-*属性即可。后面的 TOC 文本也是用的这个办法。

  • 代码块复制的实现思路:

    代码块高亮直接引用第三方插件即可,但是这个插件无法满足全部的需求 —— 我们需要修改样式,还需要增加一个代码块复制的功能:

    • 由于代码块是动态渲染的,所以无法书写静态的 HTML 结构和 CSS 样式,需要通过动态插入 dom 的方式书写自定义结构和样式

    • 浏览器提供了原生的 webapi 供我们实现复制文本的功能,但是相关的 api 只能作用在表单元素上。这里的实现思路是,监听按钮的点击事件,在点击按钮后,获取代码块中的代码文本并存入变量中,之后再将这个变量赋值给动态创建的文本域的 value,再基于该文本域调用 select 方法,选中内部文本(也即代码块内容),之后调用 document.execCommand('copy'),即可复制选中的文本。

      Note:整个过程中,文本域是不可见的,可以用绝对定位加负 left 值将文本域从页面可见区域移走。

  • TOC 的实现思路:

    TOC 有两个需求:1. 点击目录,跳转到对应的正文位置; 2. 滚动正文,联动对应的目录高亮显示。在实现相关需求之前,需要先了解 hexo 的渲染机制:在正文区域,标题是用 h 标签包裹的,并且自带值为标题的 id(比如 <h1 id="我是标题">我是标题</h1>);在目录区域(基于 hexo 提供的 toc 函数实现),所有的标题项由 a 标签包裹,并且它们的 href 是一个锚点链接的形式,值为 # + 标题(比如 <a href="#我是标题">我是标题</a>)。

    • 明白了这一点之后,第一个需求的实现其实就很简单了,直接基于锚点链接实现点击之后的正文跳转即可。

    • 比较麻烦的是第二个需求。因为我们是要在滚动正文的过程中,联动高亮显示对应的目录项,所以必须监听页面的滚动事件。一旦滚动,首先获取当前已经滚动上去的距离 x,接着获取正文中所有的标题 dom,对它们进行遍历,找出符合以下条件的 dom:要求这个 dom 离页面顶部的距离 y 减去某个偏差值 z 之后,小于 x。那么这个 dom 就是当前必须高亮的目录项对应的 dom,我们可以拿到它的 id。接着做一个判断,如果当前高亮的目录项与这个 dom 不对应(href 不等于 #id),那么就把当前高亮的目录项的高亮样式移除,同时找到应该高亮的那个目录项(通过 href 属性查找),给它添加高亮样式。

      为什么要求这个 dom 离页面顶部的距离 y 减去某个偏差值 z 之后,小于 x?先来设想正常情况,假设当前标题就在页面可见区域顶端:

      这时候是要高亮的,可以看到, yx 实际上相等,此时 y-z 就会小于 x

      当标题滚动到上边我们看不到的区域但标题对应正文还在可见区域时:

      这时候也是要高亮的,可以看到,y 本身已经比 x 小了,所以减去 z 之后肯定也是小于 x 的。

      当标题还处于页面可见区域的底部位置时:

总结

主题基本的东西都做好了,剩下的就是上传到 github,并且向 Hexo 官方站点发起 PR----这些对于我这个菜鸟来说还很陌生,所以不得不去b站找了 github 和 git 使用的相关教程。本来应该一切顺利了,但是本地这边一直报错,原来是没有先 pull 远程仓库进行同步。

当然,git 和 github 是每个技术人的必备技能,所以之后我会另外找个时间系统学习一下这两者的使用。

最后当然就是编写说明文档了,这很像以前做汉化时写的使用说明。

感触比较深的两点:一个是注意阅读源码。如果实在没有思路,可以先参考别人是怎么写的,一开始制作主题的时候很难理清项目结构,所以我选择了先看看别人是怎么写的;二个是英语的重要性——1/5的答案在百度,4/5的答案在谷歌,学会英语就意味着你找到了解决问题的另一条途径,而且无疑是更加宽广的途径。比如 Hexo 主题的制作,国内是没有人真的会去为这个而做系列视频的,但是国外有;同样地,提问题时也可以考虑选择国外平台,如果你注意了提问礼仪,很大几率问题会得到秒回。

到这里差不多就告一段落了,之后的时间我会慢慢完善和更新这个主题。目前来说用户只有我自己,所以也算是为我自己而去努力地塑造它吧。